module core_ctrl(
  input clk,
  input rst_n,

  input        id_jmp_req,
  input [31:0] id_jmp_target,
  input        exe_jmp_req,
  input [31:0] exe_jmp_target,

  input        mem_stall_req,

  input        id_rs1_bypass_vld,
  input [4:0]  id_rs1_bypass,
  input        id_rs2_bypass_vld,
  input [4:0]  id_rs2_bypass,

  input        exe_bypass_rd_vld,
  input        exe_bypass_wait_load,
  input [4:0]  exe_bypass_rd,
  input [31:0] exe_bypass_rd_data,

  input [4:0]  mem_bypass_rd,
  input        mem_bypass_rd_ena,
  input [31:0] mem_bypass_rd_data,
  input [31:0] mem_bypass_load_data,
  input        mem_bypass_load_data_vld,

  output            ctrl_id_rs1_bypass_en,
  output [31:0]     ctrl_id_rs1_bypass_data,
  output            ctrl_id_rs2_bypass_en,
  output [31:0]     ctrl_id_rs2_bypass_data,

  output reg        ctrl_if_jmp_ena,
  output reg [31:0] ctrl_if_jmp_target,

  output ctrl_if_stall,
  output ctrl_id_stall,
  output ctrl_exe_stall,
  output reg ctrl_if_flush,
  output reg ctrl_id_flush,
  output reg ctrl_exe_flush
);

  ////////////////////////////////
  //  Deal with Control Harzad  //
  ////////////////////////////////

  wire has_jmp_req;
  assign has_jmp_req = exe_jmp_req | id_jmp_req;

  always @(*) begin
    ctrl_if_jmp_target = 32'b0;
    if (exe_jmp_req) begin
      ctrl_if_jmp_target = exe_jmp_target;
    end else if (id_jmp_req) begin
      ctrl_if_jmp_target = id_jmp_target;
    end
  end

  always @(*) begin
    ctrl_if_jmp_ena = has_jmp_req;
    ctrl_id_flush = has_jmp_req;
    ctrl_if_flush = has_jmp_req;
    ctrl_exe_flush = exe_jmp_req;// | (ctrl_id_stall & ~mem_stall_req); // flush exe when id is stalled, waiting rsx load from memory
  end

  ////////////////////////////
  //  Deal with data harzad //
  ////////////////////////////
  wire rs1_exe_match;
  wire rs1_exe_bypass_match;
  wire rs1_mem_bypass_match;
  assign rs1_exe_match = (id_rs1_bypass == exe_bypass_rd) && exe_bypass_rd_vld;
  assign rs1_exe_bypass_match = rs1_exe_match && (~exe_bypass_wait_load);
  assign rs1_mem_bypass_match = (id_rs1_bypass == mem_bypass_rd) && (mem_bypass_rd_ena | mem_bypass_load_data_vld);
  assign ctrl_id_rs1_bypass_en = id_rs1_bypass_vld && (rs1_exe_bypass_match | rs1_mem_bypass_match);
  assign ctrl_id_rs1_bypass_data = rs1_exe_bypass_match? exe_bypass_rd_data:
                                   mem_bypass_rd_ena? mem_bypass_rd_data: mem_bypass_load_data;

  wire rs2_exe_match;
  wire rs2_exe_bypass_match;
  wire rs2_mem_bypass_match;
  assign rs2_exe_match = (id_rs2_bypass == exe_bypass_rd) && exe_bypass_rd_vld;
  assign rs2_exe_bypass_match = rs2_exe_match && (~exe_bypass_wait_load);
  assign rs2_mem_bypass_match = (id_rs2_bypass == mem_bypass_rd) && (mem_bypass_rd_ena | mem_bypass_load_data_vld);
  assign ctrl_id_rs2_bypass_en = id_rs2_bypass_vld && (rs2_exe_bypass_match | rs2_mem_bypass_match);
  assign ctrl_id_rs2_bypass_data = rs2_exe_bypass_match? exe_bypass_rd_data:
                                   mem_bypass_rd_ena? mem_bypass_rd_data: mem_bypass_load_data;

  assign ctrl_if_stall = ctrl_id_stall;
  assign ctrl_id_stall = mem_stall_req | ((rs1_exe_match | rs2_exe_match) & exe_bypass_wait_load);
  assign ctrl_exe_stall = mem_stall_req;

endmodule

